package com.ticket.sass.admin.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ticket.sass.admin.config.AppConfig;
import com.ticket.sass.admin.model.TokenModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Optional;


/**
 * @author ywb
 * @date 2023-02-23 13:59
 */

@Slf4j
@Component
public class JwtUtil {
    private static final String TOKEN_PREFIX = "Bearer ";
    private static final String TOKEN_HEADER = "Authorization";
    private static final long EXPIRATION_TIME = 2; // 1 day
    private static final String VALID_TOKEN_CACHE_KEY = "ticket-sass-tenant-admin-token-uid:%s";

    
    public TokenModel createToken(Long adminId, String account) {
        try {
            Instant expires = LocalDateTime.now().plusDays(EXPIRATION_TIME).toInstant(ZoneOffset.of("+8"));
            String token = JWT.create()
                .withAudience(adminId.toString())
                .withSubject(account)
                .withExpiresAt(Date.from(expires))
                .sign(Algorithm.HMAC512(AppConfig.TOKEN_SECRET));
            return new TokenModel(expires.getEpochSecond(), TOKEN_PREFIX + token);
        } catch (Exception e) {
            log.error("Error creating token: {}", e.getMessage());
            return null;
        }
    }
    
    public Optional<DecodedJWT> verify(String token) {
        try {
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC512(AppConfig.TOKEN_SECRET)).build();
            return Optional.of(jwtVerifier.verify(token));
        } catch (Exception e) {
            log.error("Error verifying token: {}", e.getMessage());
            return Optional.empty();
        }
    }
    
    public String getAuthToken(HttpServletRequest request) {
        try {
            String authToken = request.getHeader(TOKEN_HEADER);
            return authToken != null && authToken.startsWith(TOKEN_PREFIX) ? authToken.substring(TOKEN_PREFIX.length()) : "";
        } catch (Exception e) {
            log.error("Error getting auth token: {}", e.getMessage());
            return "";
        }
    }
    
    public String validTokenCacheKey(Long uid) {
        return String.format(VALID_TOKEN_CACHE_KEY, uid);
    }
    
    public Long getAudBy(HttpServletRequest request) {
        return getClaim(request, "aud").map(Long::parseLong).orElse(0L);
    }
    
    public String getSubBy(HttpServletRequest request) {
        return getClaim(request, "sub").orElse("");
    }
    
    public Optional<String> getClaim(HttpServletRequest request, String name) {
        return verify(getAuthToken(request)).flatMap(jwt -> Optional.ofNullable(jwt.getClaim(name)).map(Claim::asString));
    }
    

}
